//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <fstream>

#include "libraries.h"
#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHLINE 50000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace MatrixSpace {

  bool EqualCell(TNode <String>* NodeT, void* ref) {
    String* labelA  = NodeT->Info();
    String* labelB  = (String*)ref;
    return (*(labelA) == *(labelB))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SplitColumn(char* buffer, TListE<String>* columns, const char* characters) {

  if (!buffer || !columns || !characters) return false;

  char *part = strtok(buffer, characters);

  while (part) {
    String* cell = new String(part);
    cell->Trim();
    columns->Add(cell);
    part = strtok(NULL, characters);
  }

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main(int argc, char** argv) {

  String* filenameMatrix1;
  String* filenameMatrix2;
  String* filenameOut;

  if (argc < 4) {
    cout << "Error in the input arguments. The execution must be: " << endl;
    cout << "./CorrespondencePointInToMatrix <Input Matrix File - 1> <Input Matrix File - 2> <Output File>" << endl;
    return 0;
  }
  else {
    cout << "---------------------------------------------------------------------------------" << endl;
    cout << " Input Matrix File - 1 : " << argv[1] << endl;
    cout << " Input Matrix File - 2 : " << argv[2] << endl;
    cout << "           Output File : " << argv[3] << endl;
    cout << "---------------------------------------------------------------------------------" << endl;
    filenameMatrix1 = new String(argv[1]);
    filenameMatrix2 = new String(argv[2]);
    filenameOut     = new String(argv[3]);
  }

  double**          matrix1       = NULL;
  double**          matrix2       = NULL;

  TListE <String>*  labelsMatrix1 = new TListE <String> ();
  TListE <String>*  labelsMatrix2 = new TListE <String> ();

  TListE <String>*  column        = new TListE <String> ();

  bool              labelsRead    = true;
  int               row           = 0;
  
  char              buffer[LENGTHLINE + 1];

  gzFile fileMatrix1 = gzopen(filenameMatrix1->Out(), "rb9");

  while (!gzeof(fileMatrix1)) {
      
    gzgets(fileMatrix1, buffer, LENGTHLINE);

    column->Clear();
    SplitColumn(buffer, column, " \t\n\r");
    
    if (labelsRead) {
      matrix1 = new double*[column->Length()];
      for (int i = 0; i < column->Length(); i++) {
        matrix1[i] = new double[column->Length()];
        for (int j = 0; j < column->Length(); j++)
          matrix1[i][j] = 0;
      }

      TListE <String>* tmpList = column;
      column                   = labelsMatrix1;
      labelsMatrix1            = tmpList;
              
      labelsRead = false;
      continue;
    }

    for (int i = 0; i < column->Length(); i++)
      matrix1[row][i] = atof(column->Get(i)->Out());
    row++;

  }

  gzclose(fileMatrix1);

  gzFile fileMatrix2 = gzopen(filenameMatrix2->Out(), "rb9");
  
  row = 0; labelsRead = true;

  while (!gzeof(fileMatrix2)) {

    gzgets(fileMatrix2, buffer, LENGTHLINE);

    column->Clear();
    SplitColumn(buffer, column, " \t\n\r");

    if (labelsRead) {

      matrix2 = new double*[column->Length()];
      for (int i = 0; i < column->Length(); i++) {
        matrix2[i] = new double[column->Length()];
        for (int j = 0; j < column->Length(); j++)
          matrix2[i][j] = 0;
      }
      
      TListE <String>* tmpList = column;
      column                   = labelsMatrix2;
      labelsMatrix2            = tmpList;
      
      labelsRead = false;
      continue;
    }

    for (int i = 0; i < column->Length(); i++)
      matrix2[row][i] = atof(column->Get(i)->Out());
    row++;

  }

  gzclose(fileMatrix1);

  fstream fileResult;

  fileResult.open(filenameOut->Out(), fstream::out);

  for (int i = 0; i < labelsMatrix1->Length(); i++) {
    for (int j = 0; j < labelsMatrix1->Length(); j++) {

      String* labelA = labelsMatrix1->Get(i);
      String* labelB = labelsMatrix1->Get(j);

      long    positionMatrix2LabelA = labelsMatrix2->FirstOcurrencePosition(MatrixSpace::EqualCell, labelA);
      long    positionMatrix2LabelB = labelsMatrix2->FirstOcurrencePosition(MatrixSpace::EqualCell, labelB);

      if (positionMatrix2LabelA == -1 || positionMatrix2LabelB == -1) continue;
      if (matrix2[positionMatrix2LabelA][positionMatrix2LabelB] == 1 && matrix1[i][j] == 1) continue;

      labelA->RTrim(); labelB->RTrim();

      char labels[300];
      sprintf(labels, "%s_VS_%s\0", labelA->Out(), labelB->Out());

//      fileResult.width(22);
//      fileResult.left;
      fileResult << labels << " ";
//      fileResult.width(12);
//      fileResult.left;
      fileResult << matrix1[i][j] << " ";
//      fileResult.width(12);
//      fileResult.left;
      fileResult << matrix2[positionMatrix2LabelA][positionMatrix2LabelB] << endl;

      cout.width(22);
      cout.left;
      cout << labels << " ";
      cout.width(12);
      cout.left;
      cout << matrix1[i][j] << " ";
      cout.width(12);
      cout.left;
      cout << matrix2[positionMatrix2LabelA][positionMatrix2LabelB] << endl;
      
    }
  }

  fileResult.close();

  if (matrix1) {
    for (int i = 0; i < labelsMatrix1->Length(); i++)
      if (matrix1[i]) delete[] matrix1[i];
    delete[] matrix1;
  }

  if (matrix2) {
    for (int i = 0; i < labelsMatrix2->Length(); i++)
      if (matrix2[i]) delete[] matrix2[i];
    delete[] matrix2;
  }

  if (labelsMatrix1)   delete labelsMatrix1;
  if (labelsMatrix2)   delete labelsMatrix2;

  if (column)          delete column;
  
  if (filenameMatrix1) delete filenameMatrix1;
  if (filenameMatrix2) delete filenameMatrix2;
  if (filenameOut)     delete filenameOut;

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//




